SM4算法介绍与代码实现
本文最后更新于:2023年12月17日 下午
SM4算法介绍
加密过程
- 首先左侧描述了SM4加密的整体流程:
- 输入的一个消息分组为128bits,划分成4个小块,每个小块32bits
- 这四个小块经过32轮加密处理
- 加密处理后,再经过一次Permutation置换,得到最终加密结果
- 右侧描述其中一轮的加密过程,其他轮函数加密过程是类似的,只是轮密钥不同:
- X_3 先后跟 X_2 、X_1 进行异或 —— ①
- ① 得到的结果再与轮密钥 RK_i 进行异或 —— ②
- ② 得到的记过为32bits,再分成4组8bits,每一组8bits 使用相同的S-Box进行替换,得到新的8bits —— ③
- ③ 得到的4组8bits重新拼接得到32bits,将这32bits复制成5份输入,第1份循环左移2位,第2份循环左移10位,第3份循环左移18位,第4份循环左移24位,第5份不改动直接输出 —— ④
- ④ 的得到的5份输出的32bits与X_0 一起进行异或 —— ⑤
- 最终得到输出 X’_3 就是 ⑤ 的输出,其他输出X’_0 = X_1 , X’_1 = X_2, X’_2 = X_3
用公式进行描述如下所示,其中S代表使用S-box进行替换,L表示线性函数执行循环左移的操作
$$
X’_0 = X_1 \
X’_1 = X_2 \
X’_2 = X_3
$$
$$
X’_3 =X_0⊕ L( S (X_3 ⊕ X_2 ⊕ X_1 ⊕ RK_i))
$$
$$
A=(a_0,a_1,a_2,a_3), B=(b_0,b_1,b_2,b_3) \ (b_0,b_1,b_2,b_3) = S(A)= (Sbox(a_0),Sbox(a_1),Sbox(a_2),Sbox(a_3))
$$
$$
B=(b_0,b_1,b_2,b_3), C (32bits) \ C = L(B) = B ⊕ (B<<2) ⊕(B<<10) ⊕(B<<18)⊕(B<<24)
$$
通过观察SM4加密过程可以看到,在一轮加密中,有3个输出完全等同于3个输入,只有一个输出需要经过一些复杂操作,即计算X'_3,所以在进行解密时,只需要计算原来的X_0,而这可以通过现有的输出得到的(具体操作见下面的解密过程)。
解密过程
- 在了解了SM4一轮的加密过程后,不难得出一轮的解密过程,如下图所示
- 同样左侧描述了SM4解密的整体流程:
- 输入的一个密文C为128bits,划分成4个小块,每个小块32bits
- 对这四个小块经过一次Permutation置换
- 对置换结果进行32轮类似的解密处理,得到最终的明文输出
- 具体描述一轮的解密过程,进行32轮类似的解密操作,其中X’_0对应加密过程中的输入X_1,X’_1对应输入X_2,X’_2对应输入X_3,所以重点计算得到原来输入的X_0,下面直接用公式来表示计算过程
$$
X_1 = X’_0 \qquad X_2 = X’_1 \qquad X_3 = X’_2
$$
$$
X_0 =X’_3⊕ L( S (X’_2 ⊕ X’_1 ⊕ X’_0 ⊕ RK_i))
$$
其中L线性函数跟S-box置换 都跟加密过程中一致;但需要注意的是解密过程中,轮密钥的使用次序是(31, 30, …, 1,0),跟加密过程使用的轮密钥次序正好是相反的
轮密钥生成
- 轮密钥生成过程如上图所示,其中K代表的是16字节的密钥,公式里的S用的和加密过程中相同的Sbox
C++实现SM4加密与解密
实现目标
- 使用C++实现SM4算法的加密和结果,实现包括ECB、CBC两种加密模式。并提供命令⾏接⼝对⼆进制⽂件 进⾏加/解密。
- 实现对png图像文件的加密,只对图像数据部分进行加密,使得对加密png文件后仍能以png格式打开
命令行格式说明
- 生成的二进制可执行文件为 AppliedCryptography,共有以下几种可选配置
- -enc:进行加密操作
- -dec:进行解密操作
- -mode:指定加密/解密操作,其后跟着ecb或者cbc(如果没有指定,默认为ecb模式)
- -png:指定输入和输出文件为png格式(对png文件做特殊处理,只加密数据块部分);如果指定了,请保证文件的后缀名以.png格式结尾
- -in:输入文件的路径,请使用相对路径
- -out:输出文件的路径,请使用相对路径
- -key:指定密钥,默认为”123456”
- -iv:指定初始化向量,默认为”123456”
- -test:如果指定了,执行测试函数
1. 配置的命令请用小写
2. 一些配置之后请紧跟对应的参数值
3. 输入和输出的路径请用相对路径
- 参考的测试命令如下
1 |
|
代码结构说明
首先说明进行代码目录的说明,如下图所示:
代码目录结构
- 项目使用CMake 构建,build目录是构建目录,build/output/bin下是对应可执行文件的输出目录,build/output/bin/test 目录下存放测试用的相关文件
- Cmake-build-debug:使用CLion 编译构建时生成的目录
- FirstWork:主要目录,sm4对应源代码是算法的具体实现;test对应的是测试相关方法,主要用于测试算法的正确性
- hash-library:一个简单的第三方库,封装了hash操作和hex编码和解码等操作
- util:其中util是一个工具类,主要封装了一些辅助函数
- main.cpp:程序入口,主要实现了解析命令行参数,执行对应的操作
实现相关说明
在
sm4.h
和sm4.cpp
中实现了SM4算法,具体实现逻辑只要是拆分成多个子函数- L线性函数和Sbox替换函数实现
- 轮密钥生成
SM4EncRound
和SM4DecRound
实现一轮的加密和解密Encryption
和Decryption
实现128bits输入的加密和解密EncFile
和DecFile
实现文件的加密和解密EncPNG
和DecPNG
实现对png格式文件的加密和解密
需要注意的是,png图片文件,有自己的固定格式,主要为头部8字节固定签名,加其他数据块的结构,所以解析时要得到真正的数据块(IDAT),对这一部分进行加密,这样才能加密后依然能够以png方式打开,具体的PNG格式参考:PNG格式说明
测试函数主要有4个
TestAll()
:进行所有测试TestEncDec()
: 测试SM4 单次加解密128bitsTestEncDecFileECB()
: 测试SM4 加密和解密文件 ECB模式TestEncDecFileCBC()
: 测试SM4 加密和解密文件 CBC模式TestEncDecPNG()
: 测试SM4 加密和解密PNG图片
代码已上传Github仓库:https://github.com/2017zhangyuxuan/AppliedCryptography
但是当前代码还存在问题是,大端和小端的问题没有彻底解决,如果对比一些官方实现,加密结果是不同的,因为时间原因没有能排查出来,只能作罢。所以仅仅是提供一些思路。
参考附录
SM4算法原理 :https://blog.csdn.net/bird_tp/article/details/105988468
SM4 实现参考:https://cryptopp.com/docs/ref/class_s_m4_1_1_base.html#details